package mornd.autowired;

import lombok.ToString;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.DependencyDescriptor;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.*;
import org.springframework.core.MethodParameter;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.Optional;

/**
 * @author: mornd
 * @dateTime: 2023/5/12 - 16:23
 *
 *        @Autowired 外层装配原理
 */

@ComponentScan
public class Demo {

    public static void main(String[] args) throws Exception {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Demo.class);
        DefaultListableBeanFactory beanFactory = context.getDefaultListableBeanFactory();

        // 根据成员变量的类型注入
        DependencyDescriptor dd = new DependencyDescriptor(Emp.class.getDeclaredField("dept"), false);
        Object dept = beanFactory.doResolveDependency(dd, "emp", null, null);
        //System.out.println(dd.getDependencyType());
        System.out.println("dept " + dept);


        // 根据成员变量的类型注入 @Lazy
        DependencyDescriptor dd1 = new DependencyDescriptor(Emp.class.getDeclaredField("dept1"), false);
        // 解析 @Lazy 注解
        ContextAnnotationAutowireCandidateResolver resolver = new ContextAnnotationAutowireCandidateResolver();
        resolver.setBeanFactory(beanFactory);
        // 如果标注了 @Lazy 则返回一个代理对象，否则返回 null
        Object dept1 = resolver.getLazyResolutionProxyIfNecessary(dd1, "emp");
        System.out.println("dept1 " + dept1);
        System.out.println(dept1.getClass());


        // 根据方法参数类型注入(获取方法上的参数对象)
        MethodParameter setDept = new MethodParameter(Emp.class.getDeclaredMethod("setDept", Dept.class), 0);
        DependencyDescriptor dd2 = new DependencyDescriptor(setDept, false);
        Object dept2 = beanFactory.doResolveDependency(dd2, "emp", null, null);
        System.out.println("dept2 " + dept2);


        // 获取 Optional 类型参数
        DependencyDescriptor dd3 = new DependencyDescriptor(Emp.class.getDeclaredField("dept3"), false);
        // 增加一层内嵌
        if(dd3.getDependencyType() == Optional.class) {
            dd3.increaseNestingLevel();
            Object dept3 = beanFactory.doResolveDependency(dd3, "", null, null);
            Optional optional = Optional.ofNullable(dept3);
            System.out.println("dept3 " + optional.get());
        }


        // 获取 ObjectFactory (调用工厂的 getObject 方法时，才真正去容器中找，能推迟bean的获取)
        // ObjectProvider
        DependencyDescriptor dd4 = new DependencyDescriptor(Emp.class.getDeclaredField("dept4"), false);
        if(dd4.getDependencyType() == ObjectFactory.class) {
            dd4.increaseNestingLevel();
            ObjectFactory of = new ObjectFactory() {
                @Override
                public Object getObject() throws BeansException {
                    return beanFactory.doResolveDependency(dd4, "", null, null);
                }
            };
            System.out.println("dept4 " + of.getObject());
        }



    }

    @ToString
    @Component
    static class Emp {
        @Autowired
        private Dept dept;

        @Autowired
        @Lazy // 推迟对象的获取，创建一个代理对象，待访问对象的方法时，才会真正去容器中获取真实的对象
        private Dept dept1;

        @Autowired
        public void setDept(@Lazy Dept dept) {
            this.dept = dept;
        }

        @Autowired
        private Optional<Dept> dept3;

        @Autowired
        private ObjectFactory<Dept> dept4;
    }

    @Component
    static class Dept {
        public void foo() {
            System.out.println("foo");
        }
    }
}
